﻿using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using static NUnit.Framework.TestContext.TestAdapter;

namespace C_高级编程
{
    /// <summary>
    /// 反射 
    ///     可以看清一个类、一个对象的所有成员,而且可以调用它们。(除了似有构造函数)
    ///     对象在反射面前是没有隐私的。
    ///  反射指程序可以访问、检测和修改它本身状态或行为的一种能力。. 程序集包含模块，而模块包含类
    ///  型，类型又包含成员。. 反射则提供了封装程序集、模块和类型的对象。. 您可以使用反射动态地创建类
    //   型的实例，将类型绑定到现有对象，或从现有对象中获取类型。
    ///  反射大多是用来做框架的
    ///  反射大多是用来做框架的
    /// </summary>
    public class 反射
    {
        //获取类型
        //Type类，类型类(抽象了所有C#中的类型)
        public void test()
        {
            //用一下两种方式获取类型
                //1、通过类型名获取类型
                    Type type = typeof(StudentInfo);
                    Type type1 = typeof(int);
                    Type type2 = typeof(string);
            
            //2、通过获取获取类型
            StudentInfo studentInfo = new StudentInfo();
                    Type type3 = studentInfo.GetType();
                    string aa = "aaaaa";
                    Type type6 = aa.GetType();
                    Type type4 = 1.GetType();
                    Type type5 = "sssss".GetType();
        }

        
        /// <summary>
        /// 获取类型的属性
        /// </summary>
        public void Test1()
        {
            //获取类型的所有属性
            Type type1 = typeof(StudentInfo);
            var propertyInfos = type1.GetProperties();
            foreach (var item in propertyInfos)
            {
                Console.WriteLine($"名称:{item.Name},类型:{item.PropertyType}");
            }

            //获取类型的单个属性
            var propertyInfo1 = type1.GetProperty("Age");
        }


        /// <summary>
        /// 反射获取字段
        /// </summary>
        public void Test2()
        {
            Type type1 = typeof(StudentInfo);
            var fieldInfos = type1.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);

            foreach (var item in fieldInfos)
            {
                Console.WriteLine($"fieldName:{item.Name},fieldType:{item.FieldType}");
            }

            //获取单个字段
            var fieldInfo = type1.GetField("_studentNo", BindingFlags.Instance | BindingFlags.NonPublic);
            Console.WriteLine(fieldInfo);
        }

        [Test]
        /// <summary>
        /// 获取类型的全称信息
        /// </summary>
        public void Test3()
        {
            Type type1 = typeof(StudentInfo);

            Console.WriteLine($"type1的类名：{type1.Name}");
            Console.WriteLine($"type1的基类:{ type1.BaseType}");
            Console.WriteLine($"type1的全称:{ type1.FullName}");
            Console.WriteLine($"type1的命名空间:{ type1.Namespace}");
            
        }

        /// <summary>
        /// 用反射创建对象
        /// </summary>
        public void CreateInstance()
        {
            Type type1 = typeof (StudentInfo);
            //根据类型创建对象，底层是调用了无参构造函数，对象创建的唯一途径只能是构造函数被调用
            var instance = Activator.CreateInstance(type1) as StudentInfo;

            //根据类型创建对象，底层是调用了有参构造函数
            var instance1 = Activator.CreateInstance(type1, "任我行", 10) as StudentInfo;//再次证明Activator.CreateInstance调用的是构造函数
        }


        [Test]
        ///用反射操作属性
        public void TestOperationProp()
        { 
            Type type1 = typeof(StudentInfo);
            //通过类型获取属性
            var propInfo = type1.GetProperty("NickName");//获取属性信息
            //创建对象
            var instance = Activator.CreateInstance(type1) as StudentInfo;//创建对象
            //属性赋值(哪个对象，赋什么值)
            propInfo.SetValue(instance, "任盈盈");//设置属性的值

            Console.WriteLine(propInfo.GetValue(instance));//获取属性的值
        }

        [Test]
        //反射操作字段
        public void TestOperationField()
        {
            Assert.Equals(1, 2);
            //获取类型
            Type type1 = typeof(StudentInfo);
            //获取字段
            var field = type1.GetField("money",BindingFlags.Instance|BindingFlags.NonPublic);
            //创建对象
            var instance = Activator.CreateInstance(type1);
            //设置属性
            field.SetValue(instance, 6000);
            //获取属性
            Console.WriteLine(field.GetValue(instance));
        }


        [Test]
        public void TestAssembly()
        {
            //加载程序集
            var assembly1 = Assembly.Load("TestProject1");

            //路径加载程序集名称
            var assembly2 = Assembly.LoadFile(@"d:\路径\ClassLibrary1.dll");

            //加载程序集后创建对象
            Object obj = assembly1.CreateInstance("命名空间.类名", false);

            //获取当前正在执行的程序集完整路径
            string location = Assembly.GetExecutingAssembly().Location;

            //获取当前正在执行的程序集名称
            string  file = Assembly.GetExecutingAssembly().GetName().Name;

            //获取当前正在执行的程序集版本号
            string  version = Assembly.GetExecutingAssembly().GetName().Version.ToString();


            //TimeSpan时间段对象  FromDays只提醒天数作为时间间隔
            DateTime.Now.Subtract(TimeSpan.FromDays(30));
        }
    }



    public class StudentInfo
    {
        //公有方法
        public void Run()
        {
            Console.WriteLine($"我是{NickName},我每天都要晨跑");
        }

        //公有方法，重载
        public void Run2(int age)
        {
            Console.WriteLine($"我是{NickName},我今年{age},我每天都要晨跑");
        }

        //似有方法
        private string Run3(string nickName)
        {
            return $"我是{nickName},我是私有方法";
        }

        //无参构造
        public StudentInfo()
        {

        }
        //构造函数重载
        public StudentInfo(string nickName, int age)
        {
            NickName = nickName;
            Age = age;
        }

        //似有字段
        private string _studentNo;//字段
        private int money;
        private int Id { get; set; }//
            
        //属性
        public int Age { get; set; }
        public string NickName { get; set; }
    }
}
